Skip to content

Improve performance by rendering projects view all at once#153

Merged
dwilding merged 4 commits intocanonical:next-releasefrom
evildmp:improve-performance
Apr 28, 2026
Merged

Improve performance by rendering projects view all at once#153
dwilding merged 4 commits intocanonical:next-releasefrom
evildmp:improve-performance

Conversation

@evildmp
Copy link
Copy Markdown
Collaborator

@evildmp evildmp commented Apr 22, 2026

Depends on #150; merge that first

evildmp added 2 commits April 26, 2026 10:52
Previously, the project list was lazy-loaded with htmx. This update
restores the bulk delivery of the page, along with opportuities for
substantially reducing the number of per-row queries. With luck, this
should turn out to be fast enough in practice that we can keep this
approach.
@dwilding dwilding force-pushed the improve-performance branch from 4acce36 to 2849585 Compare April 26, 2026 02:53
@dwilding
Copy link
Copy Markdown
Collaborator

I've rebased this onto next-release and will review it this week (likely Tuesday). After reviewing, I'll merge it into next-release, then do a release based on next-release. The next PR in sequence (#155) is much bigger and needs more eyes/discussion, so I don't want that work to block the release.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to improve the performance of the project list page by reducing per-row ORM work and removing HTMX-based lazy row loading in favor of server-side rendering with precomputed data.

Changes:

  • Optimize ProjectListView queryset with select_related/prefetch_related and precompute per-project objective/QI data in bulk.
  • Remove the project_row endpoint and HTMX “intersect” row loading, rendering rows directly via a template include.
  • Add a regression test ensuring QI history, current QI, and objective levels render on the project list page.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
dashboard/projects/views.py Adds eager-loading and bulk aggregation/mapping to reduce ORM work on the list view; removes project_row view.
dashboard/projects/urls.py Removes the project_row route since rows are no longer lazily fetched.
dashboard/projects/test_views.py Adds coverage for rendering QI history/current QI and levels in the list page.
dashboard/projects/templates/projects/project_list.html Replaces HTMX lazy-loading row placeholder with direct include of the row partial.
dashboard/projects/templates/projects/partial_project_list_row.html Switches template to use the new precomputed attributes for QI history and QI total.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +40 to +49
# Build a per-project objective map once to avoid repeated row-level lookups.
pos_by_project = {}
for po in ProjectObjective.objects.all().values(
"project_id",
"objective__name",
"id",
"level_achieved__name",
"unstarted_reason__name",
):
pos_by_project.setdefault(po["project_id"], []).append(po)
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pos_by_project is built from ProjectObjective.objects.all() and without any ordering. This will load objectives for every project in the database (hurting performance on large datasets) and may render objective columns in an arbitrary order, misaligning cells with objective_list (which is ordered by Objective.Meta.ordering). Build projects/project_ids first, then query ProjectObjective with project_id__in=project_ids and an explicit order_by that matches the objective header order (e.g., objective group/name or objective_id).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator

@dwilding dwilding Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good comment, but we can disregard it:

  • Ordering - Per docs, Django will use the default ordering on the related model, in this case following our specified ordering of Project and Objective objects.
  • Performance - We want to load ProjectObjectives for every project, because we're rendering the all-projects view.

Copy link
Copy Markdown
Collaborator

@dwilding dwilding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some additional local testing to check that the rendering and new test work as expected.

@dwilding dwilding changed the title Improve performance Improve performance by rendering projects view all at once Apr 28, 2026
@dwilding dwilding merged commit ada9186 into canonical:next-release Apr 28, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants